package com.atguigu.gmall.realtime.common.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.async.RedisAsyncCommands;
import org.apache.commons.lang3.StringUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * @author Felix
 * @date 2024/8/05
 * 操作Redis的工具类
 * 旁路缓存
 *      思路：先从缓存中获取要关联的维度数据，如果从缓存中找到了维度，直接将其作为返回值进行返回；如果在缓存中没有找到要关联的维度，
 *            发送请求到HBase中进行查询，并将查询的结果放到缓存中缓存起来，方便下次查询使用。
 *      缓存产品的选型：
 *           状态           性能很好，维护性差
 *           Redis         性能也不错，维护性好       √
 *      关于Redis的一些配置
 *          key:     维度表名:主键值       例如： dim_base_trademark:1
 *          类型:     String
 *          expire:  1day    避免冷数据常驻内存，给内存带来压力
 *      注意：如果业务数据库维度表发生了变化，需要将缓存中的维度数据清除掉
 */
public class RedisUtil {
    private static JedisPool jedisPool;

    static {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMinIdle(5);
        jedisPoolConfig.setMaxTotal(100);
        jedisPoolConfig.setMaxIdle(5);
        jedisPoolConfig.setBlockWhenExhausted(true);
        jedisPoolConfig.setMaxWaitMillis(2000);
        jedisPoolConfig.setTestOnBorrow(true);
        jedisPool = new JedisPool(jedisPoolConfig,"hadoop102",6379,10000);
    }

    //获取Jedis客户端
    public static Jedis getJedis(){
        System.out.println("~~~获取Jedis客户端~~~");
        Jedis jedis = jedisPool.getResource();
        return jedis;
    }
    //关闭Jedis客户端
    public static void closeJedis(Jedis jedis){
        if(jedis != null){
            System.out.println("~~~关闭Jedis客户端~~~");
            jedis.close();
        }
    }

    //从Redis中获取维度数据
    public static JSONObject readDim(Jedis jedis,String tableName,String id){
        //拼接key
        String key = getKey(tableName, id);
        String dimJsonStr = jedis.get(key);
        if(StringUtils.isNotEmpty(dimJsonStr)){
            //缓存命中
            JSONObject dimJsonObj = JSON.parseObject(dimJsonStr);
            return dimJsonObj;
        }
        return null;
    }

    //向Redis中放维度数据
    public static void writeDim(Jedis jedis,String tableName,String id,JSONObject dimJsonObj){
        String key = getKey(tableName, id);
        jedis.setex(key,24*3600, dimJsonObj.toJSONString());
    }

    public static String getKey(String tableName, String id) {
        String key = tableName + ":" + id;
        return key;
    }


    //获取异步操作Redis的客户端
    public static StatefulRedisConnection<String,String> getRedisAsyncConnection(){
        System.out.println("~~~获取异步Redis客户端~~~");
        RedisClient redisClient = RedisClient.create("redis://hadoop102:6379/0");
        StatefulRedisConnection<String, String> asyncRedisConn = redisClient.connect();
        return asyncRedisConn;
    }
    //关闭异步操作Redis的客户端
    public static void closeRedisAsyncConnection(StatefulRedisConnection<String,String> asyncRedisConn){
        if(asyncRedisConn != null && asyncRedisConn.isOpen()){
            System.out.println("~~~关闭异步Redis客户端~~~");
            asyncRedisConn.close();
        }
    }
    //以异步的方式从Redis中读取数据
    public static JSONObject readDimAsync(StatefulRedisConnection<String,String> asyncRedisConn,String tableName,String id){
        //拼接操作Redis的key
        String key = getKey(tableName, id);
        RedisAsyncCommands<String, String> asyncCommands = asyncRedisConn.async();
        try {
            String dimJsonStr = asyncCommands.get(key).get();
            if(StringUtils.isNotEmpty(dimJsonStr)){
                JSONObject dimJsonObj = JSON.parseObject(dimJsonStr);
                return dimJsonObj;
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return null;
    }
    //以异步的方式向Redis中写入数据
    public static void writeDimAsync(StatefulRedisConnection<String,String> asyncRedisConn,String tableName,String id,JSONObject dimJsonObj){
        String key = getKey(tableName, id);
        RedisAsyncCommands<String, String> asyncCommands = asyncRedisConn.async();
        asyncCommands.setex(key,24*3600, dimJsonObj.toJSONString());
    }


    public static void main(String[] args) {
        Jedis jedis = getJedis();
        String pong = jedis.ping();
        System.out.println(pong);
    }
}
